﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using YasharEl.Infrastructure.Windows;
using System.Windows.Threading;
using System.Diagnostics.Contracts;
using YasharEl.Infrastructure.PresentationModel.Prism.Modularity;
using YasharEl.Infrastructure.ObjectFactory;
using YasharEl.Infrastructure.PresentationModel.Prism.Windows;
using YasharEl.Infrastructure.PresentationModel.Prism.Controls;
using YasharEl.Infrastructure.PresentationModel.Prism.SplashScreen;
using YasharEl.Infrastructure.PresentationModel.Prism.FileMetadata.Themes.Default.Metadata;
using YasharEl.Infrastructure.PresentationModel.Prism.FileMetadata.Controls.TitleBanner.Metadata;
using YasharEl.Infrastructure.PresentationModel.Prism.FileMetadata.Controls.SplashScreen.Metadata;
using YasharEl.Infrastructure.PresentationModel.Prism.FileMetadata.Controls.Metadata;
using System.Diagnostics;

namespace YasharEl.Infrastructure.ApplicationModel.Prism
{
    /// <summary>
    /// This class is used to launch the Calcium application.
    /// </summary>
    public class AppStarter
    {
        StartupOptions startupOptions;

        /// <summary>
        /// Gets or sets the startup options that are used for configuring 
        /// the e.g., the splash screen image.
        /// </summary>
        /// <value>The startup options.</value>
        public StartupOptions StartupOptions
        {
            get
            {
                if (startupOptions == null)
                {
                    startupOptions = new StartupOptions();
                }
                return startupOptions;
            }
            set
            {
                startupOptions = value;
            }
        }

        public virtual void Start()
        {
            Application.Current.DispatcherUnhandledException += HandleDispatcherUnhandledException;
            ISplashScreen splashScreen = null;
            try
            {
                var dictionaries = Application.Current.Resources.MergedDictionaries;

                if (!(DependencyContainer.Initialized
                    && DependencyContainer.TryResolve<ISplashScreen>(out splashScreen)))
                {
                    /* Add default splash screen style. */
                    dictionaries.AddRelativeDictionary(SplashScreenStyleXaml.RelativePackUri);

                    var splashWindow = new SplashWindow(
                            StartupOptions.SplashImagePackUri,
                            StartupOptions.SplashBlurbVisible);

                    splashScreen = splashWindow;
                }

                splashScreen.Show();
                ApplicationUtil.DoEvents();

                /* Load the resource dictionaries into the application. */
                dictionaries.AddRelativeDictionaries(
                    new[]
                        {
                            WindowDictionaryXaml.RelativePackUri,
                            ShellBannerStyleXaml.RelativePackUri,
                            StandardMenuStyleXaml.RelativePackUri,
                            StandardToolBarTrayStyleXaml.RelativePackUri
                        });

                WpfApplicationBootstrapper bootstrapper = new WpfApplicationBootstrapper();
                bootstrapper.Run();

                var shell = DependencyContainer.Resolve<IMainWindow>();
                var window = shell as Window;
                if (window != null)
                {
                    window.Show();
                }
            }
            catch (Exception ex)
            {
                HandleApplicationException(ex, false);
            }
            finally
            {
                if (splashScreen != null)
                {
                    try
                    {
                        splashScreen.Close();
                    }
                    catch (Exception ex)
                    {
                        Debug.Fail("Problem closing splash screen. " + ex, ex.StackTrace);
                        /* Suppress. */
                    }
                }
            }
        }

        /// <summary>
        /// Called when an unhandled exception occurs on the main thread.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Threading.DispatcherUnhandledExceptionEventArgs"/> 
        /// instance containing the event data.</param>
        static void HandleDispatcherUnhandledException(
            object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true;
            HandleApplicationException(e.Exception, true);
        }

        static void HandleApplicationException(Exception exception, bool allowContinue)
        {
            try
            {
                //Log.Error("Error processed by HandleApplicationException", exception);

                //				var action = new HandleApplicationExceptionAction();
                //				TaskServiceSingleton.Instance.PerformTask(action, new HandleExceptionArgument { AllowIgnore = allowContinue, Exception = exception });
            }
            catch (Exception)
            {
                //Log.Error("Unable to perform action HandleApplicationExceptionAction", ex);
                /* Suppress. */
            }
        }
    }

    public class StartupOptions
    {
        Uri splashImagePackUri;

        /// <summary>
        /// Gets or sets the splash image path.
        /// </summary>
        /// <value>The splash image path.</value>
        public Uri SplashImagePackUri
        {
            get
            {
                return splashImagePackUri;
            }
            set
            {
                Contract.Requires<ArgumentNullException>(value != null, "SplashImagePackUri could not be null.");
                splashImagePackUri = value;
            }
        }

        bool splashBlurbVisible = true;
        readonly ModuleCatalogOptions moduleCatalogOptions = new ModuleCatalogOptions();

        /// <summary>
        /// Gets or sets a value indicating whether the Fortified with Calcium text 
        /// is shown on the splash screen.
        /// </summary>
        /// <value>
        /// 	If <c>true</c> then the calcium text will be shown on the splash screen; 
        ///		otherwise it will be hidden. Default is <c>true</c>.
        /// </value>
        public bool SplashBlurbVisible
        {
            get
            {
                return splashBlurbVisible;
            }
            set
            {
                splashBlurbVisible = value;
            }
        }

        /// <summary>
        /// Gets the module catalog parameters, which allows 
        /// a list of modules to be prevented from loading.
        /// </summary>
        /// <value>The module catalog parameters.</value>
        public ModuleCatalogOptions ModuleCatalogOptions
        {
            get
            {
                return moduleCatalogOptions;
            }
        }
    }
}
